unit database_items;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, database_base,
  itemselectorframeunit, skillitemadditionaldataframeunit, LCLTranslator,
  StdCtrls, ExtCtrls, Buttons, Spin, fpjson;

type

  { TDatabaseItemsFrame }

  TDatabaseItemsFrame = class(TDatabaseBaseFrame)
    AnimationComboBox: TComboBox;
    AnimationLabel: TLabel;
    HitTypeComboBox: TComboBox;
    HitTypeLabel: TLabel;
    InvocationFlowPanel: TFlowPanel;
    InvocationGroupBox: TGroupBox;
    IsConsummableCheckBox: TCheckBox;
    DescriptionLabel: TLabel;
    DescriptionMemo: TMemo;
    GeneralSettingsFlowPanel: TFlowPanel;
    GeneralSettingsScrollBox: TScrollBox;
    IconIdLabel: TLabel;
    IconLabel: TLabel;
    IconSpeedButton: TSpeedButton;
    IsConsumablePanel: TPanel;
    HitTypePanel: TPanel;
    AnimationPanel: TPanel;
    ItemAdditionalDataFrame: TSkillItemAdditionalDataFrame;
    SuccessPercentLabel: TLabel;
    TpGainPanel: TPanel;
    RepeatPanel: TPanel;
    RepeatLabel: TLabel;
    RepeatSpinEdit: TSpinEdit;
    SuccessPanel: TPanel;
    SpeedLabel: TLabel;
    SpeedPanel: TPanel;
    PriceLabel: TLabel;
    NameEdit: TEdit;
    NameLabel: TLabel;
    NamePanel: TPanel;
    IconPanel: TPanel;
    DescriptionPanel: TPanel;
    PricePanel: TPanel;
    PriceSpinEdit: TSpinEdit;
    ScopeComboBox: TComboBox;
    OccasionComboBox: TComboBox;
    ScopeLabel: TLabel;
    MainAdditionalSplitter: TSplitter;
    OccasionLabel: TLabel;
    OccasionPanel: TPanel;
    MainInvocationSplitter: TSplitter;
    InvocationScrollBox: TScrollBox;
    SpeedSpinEdit: TSpinEdit;
    SuccessLabel: TLabel;
    SuccessSpinEdit: TSpinEdit;
    TpGainLabel: TLabel;
    TpGainSpinEdit: TSpinEdit;
    TypePanel: TPanel;
    DbItemSelectorFrame: TItemSelectorFrame;
    GeneralSettingsGroupBox: TGroupBox;
    MainContentPanel: TPanel;
    SelectorContentSplitter: TSplitter;
    TypeComboBox: TComboBox;
    TypeLabel: TLabel;
    ScopePanel: TPanel;
    procedure AnimationComboBoxChange(Sender: TObject);
    procedure DescriptionMemoChange(Sender: TObject);
    procedure HitTypeComboBoxChange(Sender: TObject);
    procedure IconSpeedButtonClick(Sender: TObject);
    procedure Init; override;
    procedure IsConsummableCheckBoxChange(Sender: TObject);
    procedure NameEditChange(Sender: TObject);
    procedure OccasionComboBoxChange(Sender: TObject);
    procedure PriceSpinEditChange(Sender: TObject);
    procedure RepeatSpinEditChange(Sender: TObject);
    procedure ScopeComboBoxChange(Sender: TObject);
    procedure SpeedSpinEditChange(Sender: TObject);
    procedure SuccessSpinEditChange(Sender: TObject);
    procedure TpGainSpinEditChange(Sender: TObject);
    procedure TypeComboBoxChange(Sender: TObject);
  private
    IsLoading: Boolean;
    SelectedId: Integer;
    procedure LoadGeneralSettings;
    procedure LoadInvocationData;
    procedure LoadIcon(Item: TJSONObject);
    function GetSelectedItem: TJSONObject;
    procedure FillItemTypes;
    procedure FillAnimations;
    procedure ResizeMemo;
  public
    procedure LoadItemData(Id: Integer);
    procedure UpdateLanguage(Code: String); override;
  end;

resourcestring
  ItemsHeader = 'Items';

implementation

uses
    languagehelper, comboboxhelper, constants, globals, iconselection, gamefont;

{$R *.lfm}

{ TDatabaseItemsFrame }

procedure TDatabaseItemsFrame.Init;
begin
  IsLoading := True;
  DbItemSelectorFrame.SetData(Db.Items, @Db.ResizeItems, @LoadItemData);
  DbItemSelectorFrame.Title := ItemsHeader;
  DbItemSelectorFrame.JsonDataType := 'application/rpgmv-items';
  DbItemSelectorFrame.CreateElementCallback := @Db.CreateEmptyItem;
  FillItemTypes;
  FillScopeComboBox(ScopeComboBox);
  FillOccasionComboBox(OccasionComboBox);
  FillHitTypeComboBox(HitTypeComboBox);
  FillAnimations;
  ItemAdditionalDataFrame.SetDatabase(Db, siadtItem);

  ResizeMemo;

  LoadItemData(1);
end;

procedure TDatabaseItemsFrame.IsConsummableCheckBoxChange(Sender: TObject);
var
  Item: TJSONObject = nil;
begin
  if not IsLoading then
    Item := GetSelectedItem;

  if Item <> nil then
    Item.Booleans['consumable'] := IsConsummableCheckBox.Checked;
end;

procedure TDatabaseItemsFrame.DescriptionMemoChange(Sender: TObject);
var
  Item: TJSONObject = nil;
begin
  if not IsLoading then
    Item := GetSelectedItem;

  if Item <> nil then
    Item.Strings['description'] := DescriptionMemo.Text;
end;

procedure TDatabaseItemsFrame.AnimationComboBoxChange(Sender: TObject);
var
  Item: TJSONObject = nil;
begin
  if not IsLoading then
    Item := GetSelectedItem;

  if Item <> nil then
    Item.Integers['animationId'] := AnimationComboBox.ItemIndex - 1;
end;

procedure TDatabaseItemsFrame.HitTypeComboBoxChange(Sender: TObject);
var
  Item: TJSONObject = nil;
begin
  if not IsLoading then
    Item := GetSelectedItem;

  if Item <> nil then
    Item.Integers['hitType'] := HitTypeComboBox.ItemIndex;
end;

procedure TDatabaseItemsFrame.IconSpeedButtonClick(Sender: TObject);
var
  Item: TJSONObject;
  IconIndex: Integer = 0;
  IconIndexJson: TJSONNumber;
begin
  Item := GetSelectedItem;
  if (Item <> nil) and Item.Find('iconIndex', IconIndexJson) then
    IconIndex := IconIndexJson.AsInteger;

  if IconSelectionForm.ShowIconSelection(IconIndex) then begin
    Item.Integers['iconIndex'] := IconSelectionForm.SelectedIconId;
    LoadIcon(Item);
  end;
end;

procedure TDatabaseItemsFrame.NameEditChange(Sender: TObject);
var
  Item: TJSONObject = nil;
begin
  if not IsLoading then
    Item := GetSelectedItem;

  if Item <> nil then begin
    Item.Strings['name'] := NameEdit.Text;
    DbItemSelectorFrame.RefreshSelectedName;
  end;
end;

procedure TDatabaseItemsFrame.OccasionComboBoxChange(Sender: TObject);
var
  Item: TJSONObject = nil;
begin
  if not IsLoading then
    Item := GetSelectedItem;

  if Item <> nil then
    Item.Integers['occasion'] := OccasionComboBox.ItemIndex;
end;

procedure TDatabaseItemsFrame.PriceSpinEditChange(Sender: TObject);
var
  Item: TJSONObject = nil;
begin
  if not IsLoading then
    Item := GetSelectedItem;

  if Item <> nil then
    Item.Integers['price'] := PriceSpinEdit.Value;
end;

procedure TDatabaseItemsFrame.RepeatSpinEditChange(Sender: TObject);
var
  Item: TJSONObject = nil;
begin
  if not IsLoading then
    Item := GetSelectedItem;

  if Item <> nil then
    Item.Integers['repeats'] := RepeatSpinEdit.Value;
end;

procedure TDatabaseItemsFrame.ScopeComboBoxChange(Sender: TObject);
var
  Item: TJSONObject = nil;
begin
  if not IsLoading then
    Item := GetSelectedItem;

  if Item <> nil then
    Item.Integers['scope'] := ScopeComboBox.ItemIndex;
end;

procedure TDatabaseItemsFrame.SpeedSpinEditChange(Sender: TObject);
var
  Item: TJSONObject = nil;
begin
  if not IsLoading then
    Item := GetSelectedItem;

  if Item <> nil then
    Item.Integers['speed'] := SpeedSpinEdit.Value;
end;

procedure TDatabaseItemsFrame.SuccessSpinEditChange(Sender: TObject);
var
  Item: TJSONObject = nil;
begin
  if not IsLoading then
    Item := GetSelectedItem;

  if Item <> nil then
    Item.Integers['successRate'] := SuccessSpinEdit.Value;
end;

procedure TDatabaseItemsFrame.TpGainSpinEditChange(Sender: TObject);
var
  Item: TJSONObject = nil;
begin
  if not IsLoading then
    Item := GetSelectedItem;

  if Item <> nil then
    Item.Integers['tpGain'] := TpGainSpinEdit.Value;
end;

procedure TDatabaseItemsFrame.TypeComboBoxChange(Sender: TObject);
var
  Item: TJSONObject = nil;
begin
  if not IsLoading then
    Item := GetSelectedItem;

  if Item <> nil then
    Item.Integers['itypeId'] := TypeComboBox.ItemIndex + 1;
end;

procedure TDatabaseItemsFrame.LoadGeneralSettings;
var
  Item: TJSONObject;
  ItemName: String = '';
  Description: String = '';
  ItemType: Integer = 1;
  Price: Integer = 0;
  Occasion: Integer = 0;
  Scope: Integer = 0;
  IsConsumable: Boolean;
  ItemTypeJson, PriceJson, ScopeJson, OccasionJson: TJSONNumber;
  ItemNameJson, DescriptionJson: TJSONString;
  IsConsumableJson: TJSONBoolean;
begin
  Item := GetSelectedItem;
  if Item = nil then
    Exit;

  if (Item <> nil) and Item.Find('name', ItemNameJson) then
    ItemName := ItemNameJson.AsString;
  NameEdit.Text := ItemName;

  LoadIcon(Item);

  if (Item <> nil) and Item.Find('description', DescriptionJson) then
    Description := DescriptionJson.AsString;
  DescriptionMemo.Text := Description;

  if (Item <> nil) and Item.Find('itypeId', ItemTypeJson) then
    ItemType := ItemTypeJson.AsInteger;
  TypeComboBox.ItemIndex := ItemType - 1;

  if (Item <> nil) and Item.Find('price', PriceJson) then
    Price := PriceJson.AsInteger;
  PriceSpinEdit.Value := Price;

  if (Item <> nil) and Item.Find('consumable', IsConsumableJson) then
    IsConsumable := IsConsumableJson.AsBoolean;
  IsConsummableCheckBox.Checked := IsConsumable;

  if (Item <> nil) and Item.Find('scope', ScopeJson) then
    Scope := ScopeJson.AsInteger;
  ScopeComboBox.ItemIndex := Scope;

  if (Item <> nil) and Item.Find('occasion', OccasionJson) then
    Occasion := OccasionJson.AsInteger;
  OccasionComboBox.ItemIndex := Occasion;
end;

procedure TDatabaseItemsFrame.LoadInvocationData;
var
  Item: TJSONObject;
  Speed: Integer = 0;
  Success: Integer = 0;
  Repeats: Integer = 0;
  TpGain: Integer = 0;
  HitType: Integer = 0;
  AnimationId: Integer = 0;
  SpeedJson, SuccessJson, RepeatsJson, TpGainJson, AnimationIdJson, HitTypeJson:
    TJSONNumber;
begin
  Item := GetSelectedItem;
  if Item = nil then
    Exit;

  if (Item <> nil) and Item.Find('speed', SpeedJson) then
    Speed := SpeedJson.AsInteger;
  SpeedSpinEdit.Value := Speed;

  if (Item <> nil) and Item.Find('successRate', SuccessJson) then
    Success := SuccessJson.AsInteger;
  SuccessSpinEdit.Value := Success;

  if (Item <> nil) and Item.Find('repeats', RepeatsJson) then
    Repeats := RepeatsJson.AsInteger;
  RepeatSpinEdit.Value := Repeats;

  if (Item <> nil) and Item.Find('tpGain', TpGainJson) then
    TpGain := TpGainJson.AsInteger;
  TpGainSpinEdit.Value := TpGain;


  if (Item <> nil) and Item.Find('hitType', HitTypeJson) then
    HitType := HitTypeJson.AsInteger;
  HitTypeComboBox.ItemIndex := HitType;

  if (Item <> nil) and Item.Find('animationId', AnimationIdJson) then
    AnimationId := AnimationIdJson.AsInteger;
  AnimationComboBox.ItemIndex := AnimationId;
end;

procedure TDatabaseItemsFrame.LoadIcon(Item: TJSONObject);
var
  IconId: Integer = 0;
  IconIdJson: TJSONNumber;
  IconBitmap: TBitmap;
begin
  if (Item <> nil) and Item.Find('iconIndex', IconIdJson) then
    IconId := IconIdJson.AsInteger;

  IconIdLabel.Caption := IntToStr(IconId);
  if IconId <> 0 then begin
    IconBitmap := Game.GetIcon(IconId);
    IconSpeedButton.Glyph.Assign(IconBitmap);
    IconBitmap.Free;
  end else
    IconSpeedButton.Glyph.Clear;
end;

function TDatabaseItemsFrame.GetSelectedItem: TJSONObject;
begin
  GetSelectedItem := nil;
  if Db.Items = nil then
    Exit;
  if (SelectedId >= 1) and (SelectedId < Db.Items.Count) then
    GetSelectedItem := Db.Items.Objects[SelectedId];
end;

procedure TDatabaseItemsFrame.FillItemTypes;
begin
  with TypeComboBox.Items do begin
    BeginUpdate;
    Clear;
    Add(ItemTypeNormal);
    Add(ItemTypeKey);
    Add(ItemTypeHiddenA);
    Add(ItemTypeHiddenB);
    EndUpdate;
  end;
end;

procedure TDatabaseItemsFrame.FillAnimations;
  //TODO: unify this with code from Database_Skills
var
  I: Integer;
begin
  if (Db = nil) or (Db.Animations = nil) then
    Exit;

  with AnimationComboBox.items do begin
    BeginUpdate;
    Clear;
    Append(AnimationNormalAttack);
    Append(AnimationNone);
    for I := 1 to Db.Animations.Count -1 do begin
      Append(Db.GetAnimName(I));
    end;
    EndUpdate;
  end;
end;

procedure TDatabaseItemsFrame.ResizeMemo;
begin
  DescriptionMemo.Font.BeginUpdate;
  DescriptionMemo.Font.Name := GetMonospacedFontName;
  DescriptionMemo.Font.Size := GetMonospacedFontSize;
  DescriptionMemo.Font.EndUpdate;
  ResizeMemoForFont(DescriptionMemo, 55, 2);
end;

procedure TDatabaseItemsFrame.LoadItemData(Id: Integer);
begin
  IsLoading := True;
  SelectedId := Id;

  LoadGeneralSettings;
  LoadInvocationData;
  ItemAdditionalDataFrame.SetItem(Id);

  IsLoading := False;
end;

procedure TDatabaseItemsFrame.UpdateLanguage(Code: String);
begin
  inherited UpdateLanguage(Code);

  if IsLanguageRtl(Code) then begin
    GeneralSettingsFlowPanel.FlowStyle := fsRightLeftTopBottom;
    InvocationFlowPanel.FlowStyle := fsRightLeftTopBottom;
  end else begin
    GeneralSettingsFlowPanel.FlowStyle := fsLeftRightTopBottom;
    InvocationFlowPanel.FlowStyle := fsLeftRightTopBottom;
  end;
end;

end.

